<template>
  <div
    class="container"
    :style="{ height: containerHeight }"
    @scroll="handleScroll"
    ref="container"
  >
    <!-- 数据列表 -->
    <div
      class="list"
      :style="{ top: listTop }"
    >
      <!-- 列表项 -->
      <div
        v-for="item in showData"
        :key="item.id"
        :style="{ height: size + 'px' }"
      >
        {{ item.content }}
      </div>

      <!-- 用于撑开高度的元素 -->
      <div
        class="bar"
        :style="{ height: barHeight }"
      />
    </div>
  </div>
</template>

<script setup>
// ------------------------------------- 导入模块 ----------------------------------
// 导入 vue3 的 API
import { ref, toRefs, computed } from 'vue'

// ------------------------------------- 组件传值 ----------------------------------
// 接收父组件传递的数据
const props = defineProps({
  // 要渲染的数据
  items: {
    type: Array,
    required: true
  },
  // 每条数据渲染的节点的高度
  size: {
    type: Number,
    required: true
  },
  // 每次渲染的 DOM 节点个数
  shownumber: {
    type: Number,
    required: true
  }
})
// 使用 toRefs 包裹 props，让解构获得的父组件传递的参数变为响应式的
const { items, size, shownumber } = toRefs(props)

// ------------------------------------- 声明变量 ----------------------------------
const container = ref(null) // 页面 container 节点
let start = ref(0) // 要展示的数据的起始下标
let end = ref(shownumber.value) // 要展示的数据的结束下标

// ------------------------------------- 计算属性 ----------------------------------
const showData = computed(() => items.value.slice(start.value, end.value)) // 最终筛选出的要展示的数据
const containerHeight = computed(() => size.value * shownumber.value + 'px') // 容器的高度
const barHeight = computed(() => size.value * items.value.length + 'px') // 撑开容器内容高度的元素的高度
const listTop = computed(() => start.value * size.value + 'px') // 列表向上滚动时要动态改变 top 值

// ------------------------------------- 声明函数 ----------------------------------
// 容器的滚动事件
const handleScroll = () => {
  // 获取容器顶部滚动的尺寸
  const scrollTop = container.value.scrollTop

  // 计算卷去的数据条数，用计算的结果作为获取数据的起始和结束下标
  // 起始的下标就是卷去的数据条数，向下取整
  start.value = Math.floor(scrollTop / size.value)
  // 结束的下标就是起始的下标加上要展示的数据条数
  end.value = start.value + shownumber.value
}
</script>

<style scoped>
.container {
  position: relative;
  overflow-y: scroll;
  background-color: rgb(150, 195, 238);
  font-size: 20px;
  font-weight: bold;
  line-height: 60px;
  text-align: center;
}

.list {
  position: absolute;
  top: 0;
  width: 100%;
}
</style>
